#!/usr/bin/perl -w
#
# This code is from Gtk2/gtk-demo (original name is hypertext.pl).
# Some modified by Yoshizumi Endo.
# License: LGPL-2.1
#
#   Copyright (C) 2003-2008 by the gtk2-perl team
#

# Text Widget/Hypertext
#
# Usually, tags modify the appearance of text in the view, e.g. making it 
# bold or colored or underlined. But tags are not restricted to appearance. 
# They can also affect the behavior of mouse and key presses, as this demo 
# shows.
#

package Twitim::HyperText;

use strict;
use warnings;
use Glib qw(TRUE FALSE);
use Gtk2;
use Gtk2::Gdk::Keysyms;
use Twitim::Twitim;
use Exporter;

our @ISA = qw(Exporter);
our @EXPORT = qw(event_after motion_notify_event visibility_notify_event);

our $Hovering_Over_Link = FALSE;
our $Force_Auto_Scroll;

# Looks at all tags covering the position of iter in the text view, 
# and if one of them is a link, follow it by showing the page identified
# by the data attached to it.
#
# Modified by Yosizumi Endo
#
sub follow_if_link {
  my ($text_view, $iter) = @_;

  foreach my $tag ($iter->get_tags) {
      my $tagname= $tag->get_property ('name');
      $tagname ||='';

      if ($tagname =~ /url|uname/) {
          my $string = get_tagged_text($text_view, $iter, $tag);
          my $twitter_url = "http://twitter.com/";

          if ($string =~ /^#.*/) {
              $string =~ tr/#//d;
              $string = $twitter_url . "#search?q=%23" . $string;
          }
          elsif ($string !~ /http/) {
              $string =~ s{Direct from }{};
              $string =~ tr/@:() //d;
              $string = $twitter_url . $string;
          }

          open_url ($string);
          last;
      }
  }
}

# Links can be activated by pressing Enter.
#
sub key_press_event {
  my ($text_view, $event) = @_;

  if ($event->keyval == $Gtk2::Gdk::Keysyms{Return} ||
      $event->keyval == $Gtk2::Gdk::Keysyms{KP_Enter})
    {
        my $buffer = $text_view->get_buffer;
        my $iter = $buffer->get_iter_at_mark ($buffer->get_insert);
        follow_if_link ($text_view, $iter);
    }

  return FALSE;
}

# Links can also be activated by clicking.
#
sub event_after {
  my ($text_view, $event) = @_;

  return FALSE unless $event->type eq 'button-release'; 
  return FALSE unless $event->button == 1;

  my $buffer = $text_view->get_buffer;

  # we shouldn't follow a link if the user has selected something
  my ($start, $end) = $buffer->get_selection_bounds;
  return FALSE if defined $end
                  and $start->get_offset != $end->get_offset;

  my ($x, $y) = $text_view->window_to_buffer_coords ('widget', #GTK_TEXT_WINDOW_WIDGET,
                                                     $event->x, $event->y);

  my $iter = $text_view->get_iter_at_location ($x, $y);

  follow_if_link ($text_view, $iter);

  return FALSE;
}

# Looks at all tags covering the position (x, y) in the text view, 
# and if one of them is a link, change the cursor to the "hands" cursor
# typically used by web browsers.
#
# Modified by Yosizumi Endo
#
my $old_tagname = "";
my $hover_timer;

sub set_cursor_if_appropriate {
  my ($self, $text_view, $x, $y) = @_;
  my $hovering = FALSE;
  my $tagname = "";
  my $tag;

  my $buffer = $text_view->get_buffer;
  my $iter = $text_view->get_iter_at_location ($x, $y);

  foreach $tag ($iter->get_tags) {
      $tagname = $tag->get_property ('name');
      $tagname ||= '';

      if ($tagname =~ /url|uname/) 
        {
          $hovering = TRUE;
          last;
        }
  }

  if ($hovering != $Hovering_Over_Link or $old_tagname ne $tagname)
    {
      my $hand_cursor = Gtk2::Gdk::Cursor->new ('hand2');
      my $regular_cursor = Gtk2::Gdk::Cursor->new ('xterm');

      $Hovering_Over_Link = $hovering;
      $old_tagname = $tagname;

      $text_view->get_window ('text')->set_cursor
               ($Hovering_Over_Link ? $hand_cursor : $regular_cursor);

      # $textview, $x, $y, $Hovering_Over_Link, $tag, $tagname

      $self->show_link_info($Hovering_Over_Link, $text_view, 
                            $x, $y, $tag, $tagname);

      if (! $Hovering_Over_Link && defined $Force_Auto_Scroll ) 
        {
          $self->buffer_auto_scroll($Force_Auto_Scroll, 1);
        }

      # timer for unlocking scroll stop mode
      if ($Hovering_Over_Link) {
          $hover_timer = AnyEvent->timer(
              after => 30,
              cb    => sub {
                  # print "unlock\n";
                  $Hovering_Over_Link = FALSE;
                  $self->show_link_info(FALSE);
                  $self->buffer_auto_scroll( undef, 1, $text_view );
              }
              );
      }
      else {
          undef $hover_timer;
      }
    }
}

# Update the cursor image if the pointer moved. 
#
# Modified by Yosizumi Endo
#
sub motion_notify_event {
  my ($self, $text_view, $event) = @_;

  my ($x, $y) = $text_view->window_to_buffer_coords ( 
                                         'widget', #GTK_TEXT_WINDOW_WIDGET,
                                         $event->x, $event->y);

  set_cursor_if_appropriate ($self, $text_view, $x, $y);

  $text_view->window->get_pointer;
  return FALSE;
}

# Also update the cursor image if the window becomes visible
# (e.g. when a window covering it got iconified).
#
# Modified by Yosizumi Endo
#
sub visibility_notify_event {
  my ($self, $text_view, $event) = @_;

  my (undef, $wx, $wy, undef) = $text_view->window->get_pointer;
  
  my ($bx, $by) = $text_view->window_to_buffer_coords ( 
                                         'widget', #GTK_TEXT_WINDOW_WIDGET,
                                         $wx, $wy);

  set_cursor_if_appropriate ($self, $text_view, $bx, $by);

  return FALSE;
}

1;
